/*
 * @Author: hx 2542123711@QQ.com
 * @Date: 2024-12-15 17:04:59
 * @LastEditors: hx 2542123711@QQ.com
 * @LastEditTime: 2024-12-15 20:00:02
 * @FilePath: /class_thread/thread-ringqueue/RingQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include<iostream>
#include<vector>
#include<pthread.h>
#include<semaphore.h>

using namespace std;

const int defaultcap = 5;

template<class T>
class RingQueue
{
private:
    void P(sem_t& sem)
    {
        //申请信号量
        sem_wait(&sem);
    }
    void V(sem_t& sem)
    {
        //释放信号量
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t& mutex)   
    {
        pthread_mutex_lock(&mutex);
    }

    void UnLock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap = defaultcap)
    :_cap(cap), _pstep(0), _cstep(0)
    {
        _ringqueue.resize(cap);

        sem_init(&_pspace_sem, 0, cap);
        sem_init(&_cdata_sem, 0, 0);

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);
    }

    void push(const T& in)
    {
        //申请生产信号量(原子操作)，也就是对space做--
        P(_pspace_sem);
        Lock(_pmutex);//保证在多个生产者同时申请到信号量的情况下，一份临界资源只允许一个线程访问

        _ringqueue[_pstep] = in;

        _pstep++;
        _pstep %= _cap;

        UnLock(_pmutex);

        //释放数据信号量也就是对data做++
        V(_cdata_sem);
    }

    void pop(T* out)
    {
        P(_cdata_sem);
        Lock(_cmutex);

        *out = _ringqueue[_cstep];
        _cstep++;
        _cstep %= _cap;
        
        UnLock(_cmutex);
        
        V(_pspace_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_pspace_sem);
        sem_destroy(&_cdata_sem);
        
        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }
private:
    vector<T> _ringqueue;
    int _cap;

    int _pstep;
    int _cstep;

    sem_t _pspace_sem;
    sem_t _cdata_sem;

    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;
};